package com.yanyun.yczyy.api.utils;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.FormatSchema;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.json.JsonReadFeature;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.databind.type.CollectionType;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;

public class MyJsonTools {
    protected static final MyObjectMapper objectMapper = new MyObjectMapper();
    static {
        objectMapper.configure(JsonReadFeature.ALLOW_UNESCAPED_CONTROL_CHARS.mappedFeature(), true);
    }

    public static JsonNode readTree(String json) throws IOException {
        return objectMapper.readTree(json);
    }

    public static JsonNode readTree(InputStream stream) throws IOException {
        return objectMapper.readTree(stream);
    }

    public static void setSerializationInclusion(JsonInclude.Include inclusion) {
        objectMapper.setSerializationInclusion(inclusion);
    }

    public static byte[] toArray(Object o) throws JsonProcessingException {
        return objectMapper.writeValueAsBytes(o);
    }

    public static String toJsonStrict(Object o) throws JsonProcessingException {
        return objectMapper.writeValueAsString(o);
    }

    public static String toJson(Object o) throws JsonProcessingException {
        objectMapper.setDefaultPropertyInclusion(JsonInclude.Include.NON_EMPTY);
        return objectMapper.writeValueAsString(o);
    }

    public static <T> T getEntity(Class<T> clazz, String json) throws JsonProcessingException {
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        return objectMapper.readValue(json, clazz);
    }

    public static <T> T getEntityStrict(Class<T> clazz, String json) throws JsonProcessingException {
        return objectMapper.readValue(json, clazz);
    }

    public static <T> T getEntity(Class<T> clazz, InputStream is) throws IOException {
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        return objectMapper.readValue(is, clazz);
    }

    public static <T> T getEntityStrict(Class<T> clazz, InputStream is) throws IOException {
        return objectMapper.readValue(is, clazz);
    }

    public static <T> T getEntity(TypeReference<T> typeReference, String json) throws IOException {
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        return objectMapper.readValue(json, typeReference);
    }

    public static <T> T getEntity(TypeReference<T> typeReference, InputStream json) throws IOException {
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        return objectMapper.readValue(json, typeReference);
    }

    public static <T> List<T> getEntityList(Class<T> clazz, String json) throws IOException {
        CollectionType collectionType = objectMapper.getTypeFactory().constructCollectionType(List.class, clazz);
        return (List)objectMapper.readValue(json, collectionType);
    }

    public static <T> List<T> getEntityList(Class<T> clazz, InputStream inputStream) throws IOException {
        CollectionType collectionType = objectMapper.getTypeFactory().constructCollectionType(List.class, clazz);
        return (List)objectMapper.readValue(inputStream, collectionType);
    }

    public static <T> T getEntityAllBackSlashEscapingAny(Class<T> clazz, String json) throws IOException {
        objectMapper.configure(JsonParser.Feature.ALLOW_BACKSLASH_ESCAPING_ANY_CHARACTER, true);
        return objectMapper.readValue(json, clazz);
    }

    public static <T> void update(T target, String json) throws IOException {
        ObjectReader objectReader = objectMapper.readerForUpdating(target);
        objectReader.readValue(json);
    }

    public static <T> void update(T target, InputStream is) throws IOException {
        ObjectReader objectReader = objectMapper.readerForUpdating(target);
        objectReader.readValue(is);
    }

    public static <T> void update(TypeReference<T> valueTypeRef, T target, String json) throws IOException {
        ObjectReader objectReader = objectMapper.readerForCustomClassUpdating(valueTypeRef, target);
        objectReader.readValue(json);
    }

    static {
        objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
    }

    private static class MyObjectMapper extends ObjectMapper {
        private MyObjectMapper() {
        }

        public <T> ObjectReader readerForCustomClassUpdating(TypeReference<T> valueTypeRef, T valueToUpdate) {
            JavaType t = this._typeFactory.constructType(valueTypeRef);
            return this._newReader(this.getDeserializationConfig(), t, valueToUpdate, (FormatSchema)null, this._injectableValues);
        }
    }

}
